package command

import (
	"encoding/json"
	"fmt"
	"gitee.com/gitee-go/core/common"
	"gitee.com/gitee-go/utils"
	"gopkg.in/alecthomas/kingpin.v2"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"
	"time"
)

func Run() {
	app := kingpin.New("Gitee GO", "This is exec agent")
	app.Flag("debug", "").Hidden().BoolVar(&common.IsDebug)
	app.Flag("env", "set default env").
		StringsVar(&daemonCmd.cmdconf.Env)

	app.Flag("addr", "server address. (default:\"server:7030\")").
		StringVar(&daemonCmd.cmdconf.ServAddr)
	app.Flag("plugin", "step supported plugin (default:\"shell@sh\")").
		StringsVar(&daemonCmd.cmdconf.Plugin)
	app.Flag("secret", "server config runner.secret,can't register on server if it's wrong").
		StringVar(&daemonCmd.cmdconf.Secret)
	app.Flag("work", "machine pipeline workspace path. (default:\"$HOME/.giteeGo/runner)\"").
		StringVar(&daemonCmd.cmdconf.Workspace)
	app.Flag("limit", "pipeline limit number. (default:10)").
		IntVar(&daemonCmd.cmdconf.Limit)

	regDaemon(app)
	kingpin.Version(Version)
	kingpin.MustParse(app.Parse(os.Args[1:]))
}

var daemonCmd = &daemonCommand{}

func regDaemon(app *kingpin.Application) {
	path := filepath.Join(utils.HomePath(), ".giteeGo", "runner")
	if err := os.MkdirAll(path, 0750); err != nil {
		println("runner path err:", err.Error())
		return
	}
	daemonCmd.path = path

	cmd := app.Command("run", "run the runner").
		Default().
		Action(func(context *kingpin.ParseContext) error {
			return daemonCmd.start()
		})
	cmd.Arg("alias", "config name(default:default)").
		Default().
		StringVar(&daemonCmd.alias)

	cmd = app.Command("start", "start the runner daemon").
		Action(startFun)
	cmd.Arg("alias", "config name(default:default)").
		Default().
		StringVar(&daemonCmd.alias)

	cmd = app.Command("stop", "stop the runner daemon").
		Action(stopFun)
	cmd.Arg("alias", "config name(default:default)").
		Default().
		StringVar(&daemonCmd.alias)

	cmd = app.Command("status", "status the runner daemon").
		Action(statusFun)
	cmd.Arg("alias", "config name(default:default)").
		Default().
		StringVar(&daemonCmd.alias)

	cmd = app.Command("restart", "restart the runner daemon").
		Action(restartFun)
	cmd.Arg("alias", "config name(default:default)").
		Default().
		StringVar(&daemonCmd.alias)

	cmd = app.Command("envs", "").
		Action(envsFun).Hidden()
	cmd.Arg("flpth", "config name(default:default)").
		Default().
		StringVar(&envsflpth)
}

var needStartCheck = true

func startFun(context *kingpin.ParseContext) error {
	/*if needStartCheck {
		if err := statusFun(context); err == nil {
			println("the alias is running!!!!")
			return errors.New("the alias is running")
		}
	}*/
	fullpth, err := os.Executable()
	if err != nil {
		return err
	}
	pidpth := filepath.Join(daemonCmd.path, fmt.Sprintf("%s.pid", daemonCmd.Alias()))
	err = os.RemoveAll(pidpth)
	if err != nil {
		return err
	}
	pidfl, err := os.OpenFile(pidpth, os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		return err
	}
	defer pidfl.Close()

	err = daemonCmd.config()
	if err != nil {
		return err
	}

	args := make([]string, 0)
	args = append(args, "run")
	args = append(args, daemonCmd.Alias())
	if common.IsDebug {
		args = append(args, "--debug")
	}
	println("start process alias:", daemonCmd.Alias())
	cmd := exec.Command(fullpth, args...)
	//cmd.Stdout=os.Stdout
	//cmd.Stderr=os.Stderr
	err = cmd.Start()
	if err != nil {
		return err
	}

	_, err = pidfl.WriteString(fmt.Sprintf("%d", cmd.Process.Pid))
	return err
}
func stopFun(context *kingpin.ParseContext) error {
	pidpth := filepath.Join(daemonCmd.path, fmt.Sprintf("%s.pid", daemonCmd.Alias()))
	bts, err := ioutil.ReadFile(pidpth)
	if err != nil {
		return err
	}

	pid, err := strconv.Atoi(string(bts))
	if err != nil {
		return err
	}

	proc, err := os.FindProcess(pid)
	if err != nil {
		return err
	}
	println("first end process pid:", proc.Pid)
	err = proc.Signal(syscall.SIGINT)
	time.Sleep(time.Second)
	proc, err = os.FindProcess(pid)
	if err == nil {
		println("second end process pid:", proc.Pid)
		err = proc.Kill()
		time.Sleep(time.Second)
	}
	return nil
}
func statusFun(context *kingpin.ParseContext) error {
	pidpth := filepath.Join(daemonCmd.path, fmt.Sprintf("%s.pid", daemonCmd.Alias()))
	bts, err := ioutil.ReadFile(pidpth)
	if err != nil {
		return err
	}

	pid, err := strconv.Atoi(string(bts))
	if err != nil {
		return err
	}

	proc, err := os.FindProcess(pid)
	if err != nil {
		return err
	}
	println("FindProcess pid:", proc.Pid)
	return nil
}
func restartFun(context *kingpin.ParseContext) error {
	needStartCheck = false
	err := statusFun(context)
	if err == nil {
		err = stopFun(context)
		if err != nil {
			println("stop err:" + err.Error())
			return err
		}
	}
	return startFun(context)
}

var envsflpth string

func envsFun(context *kingpin.ParseContext) error {
	if envsflpth == "" {
		println("file path is empty")
		return nil
	}

	sysenvs := os.Environ()
	mapenvs := make(map[string]string)
	for _, v := range sysenvs {
		i := strings.Index(v, "=")
		if i > 0 {
			k := v[:i]
			mapenvs[k] = v[i+1:]
		}
	}
	bts, err := json.Marshal(mapenvs)
	if err != nil {
		println("get envs err:" + err.Error())
		return err
	}
	os.RemoveAll(envsflpth)
	ioutil.WriteFile(envsflpth, bts, 0640)
	return nil
}
